<?
/*! \brief Asterisk manager class */
class ami {
	/*! Default username. */
	var $astuser='admin';
	/*! Default password. */
	var $astpass='amp111';
	/*! Socket connection handler */
	var $socket;

	/*! \brief Open a connection to the Asterisk manager.
	 *  \param username Asterisk manager Username.
	 *  \param password Asterisk manager Password.
	 *  \param hostname Asterisk manager hostname (defaults to 'localhost').
	 *  \param port Asterisk manager port (defaults to 5038).
	 *  \retval true on success.
	 *  \retval false on error or authentication failure.
	*/
	function open($username = null, $password = null, $hostname = "127.0.0.1", $port = 5038) {
		$this->astuser = $username ? $username : $this->astuser;
		$this->astpass = $password ? $password : $this->astpass;
		$this->hostname = $hostname ? $hostname : $this->hostname;
		$this->astport = $port ? $port : $this->astport;
		if ($this->socket) {
			$this->close();
		}
		if ($this->socket = fsockopen($this->hostname, $this->astport, $errno, $errstr, 10)) {
			stream_set_timeout($this->socket, 2);
			$response = $this->request (
				"LOGIN",
				array(
					"USERNAME" => $this->astuser,
					"SECRET" => $this->astpass,
					"EVENTS" => ($this->events?"OFF":"ON")
				)
			);

			$response = explode("\n",$response);
			$response = $response[count($response)-4];
			$space    = strpos($response," ");
			$response = trim(substr($response,$space,strlen($response))," ");

			if ($response=="Error\r") {
				$this->socket = null;
				return false;
			} else {
				return true;
			}
		} else {
			return false;
		}
	}

	/*! \brief Close the manager connection. */
	function close() {
		$this->request("LOGOFF");
		fclose($this->socket);
		$this->socket = null;
	}

	/*! \brief Send a request to the asterisk manager. */
	function request($action, $params = null) {
		if ($this->post($action, $params)) {
			return $this->wait_for_response();
		} else {
			return false;
		}
	}

	/*! \brief helper function used to send a request to the asterisk manager. */
	function post($action, $params = null) {
		if ($this->socket !== false) {
			$request_params = "";
			if (is_array($params)) {
				foreach ($params as $key => $value) {
					$request_params .= "$key: $value\r\n";
				}
			} else {
				$request_params = $params;
			}
			$request = "ACTION: $action\r\n$request_params\r\n";
			fputs($this->socket, $request);
			return $request;
		} else {
			return false;
		}
	}

	/*! \brief Wait for a response for the last action. */
	function wait_for_response() {
		$response = false;
		while (!$response && $meta["timed_out"] == false) {
			$response = $this->read_anything();
			if (preg_match("/^Event\\:/", $response)) {
				$this->event_buffer[] = $response;
				$response = false;
			}
			$meta = stream_get_meta_data($this->socket); 
		}
		return $response;
	}

	/*! \brief Read from the socket. */
	function read_anything() {
		$line = "";
		$buffer = "";
		while ($line != "\r\n" && $meta["timed_out"] == false) {
			$line = fgets($this->socket, 4096);
			$meta = stream_get_meta_data($this->socket);
			$buffer .= $line;
		}
		return $buffer;
	}

	function events_check() {
		if ($this->socket) {
			while($this->checkbuffer()) {
				$this->event_buffer[] = $this->read_anything();
			}
		}
		return count($this->event_buffer);
	}

	function checkbuffer() {
		$pArr = array($this->socket);
		if (false === ($num_changed_streams = stream_select($pArr, $write = NULL, $except = NULL, 0))) {
			return FALSE;
		} elseif ($num_changed_streams > 0) {
			return true;
		} else {
			return false;
		}
	}

	function events_shift() {
		return array_shift($this->event_buffer);
	}

	function events_pop() {
		return array_pop($this->event_buffer);
	}
}
?>
